package org.gdstash.db;

import org.gdstash.util.GDMsgFormatter;
import org.gdstash.util.GDMsgLogger;

import java.sql.*;
import java.util.LinkedList;
import java.util.List;

public class DBLootTableItemAlloc {
    private static final String TABLE_NAME = "GD_LOOTTABLE_ITEM";
    private static final int ROW_TABLE_ID = 1;
    private static final int ROW_ITEM_ID = 2;
    private String tableID;
    private String itemID;

    public DBLootTableItemAlloc() {
        this.tableID = null;
        this.itemID = null;
    }

    public DBLootTableItemAlloc(final String tableID, final String itemID) {
        this.tableID = tableID;
        this.itemID = itemID;
    }

    public String getTableID() {
        return this.tableID;
    }

    public String getItemID() {
        return this.itemID;
    }

    public static void createTable() throws SQLException {
        final String dropTable = "DROP TABLE GD_LOOTTABLE_ITEM";
        final String createTable = "CREATE TABLE GD_LOOTTABLE_ITEM (TABLE_ID    VARCHAR(256) NOT NULL, ITEM_ID     VARCHAR(256) NOT NULL, PRIMARY KEY (TABLE_ID, ITEM_ID))";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final Statement st = conn.createStatement()) {
                if (GDDBUtil.tableExists(conn, "GD_LOOTTABLE_ITEM")) {
                    st.execute(dropTable);
                }
                st.execute(createTable);
                st.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                final Object[] args = {"GD_LOOTTABLE_ITEM"};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_CREATE_TABLE", args);
                GDMsgLogger.addError(msg);
                throw ex;
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static void delete(final Connection conn, final String tableID) throws SQLException {
        final String deleteEntry = "DELETE FROM GD_LOOTTABLE_ITEM WHERE TABLE_ID = ?";
        try (final PreparedStatement ps = conn.prepareStatement(deleteEntry)) {
            ps.setString(1, tableID);
            ps.executeUpdate();
            ps.close();
        } catch (SQLException ex) {
            throw ex;
        }
    }

    public static void insert(final Connection conn, final DBLootTable dbTable) throws SQLException {
        if (dbTable.getItemAllocList() == null) {
            return;
        }
        if (dbTable.getItemAllocList().isEmpty()) {
            return;
        }
        final String insert = "INSERT INTO GD_LOOTTABLE_ITEM VALUES (?,?)";
        try (final PreparedStatement ps = conn.prepareStatement(insert)) {
            for (final DBLootTableItemAlloc item : dbTable.getItemAllocList()) {
                try {
                    ps.setString(1, dbTable.getTableID());
                    ps.setString(2, item.itemID);
                    ps.executeUpdate();
                } catch (SQLIntegrityConstraintViolationException ex) {
                    if (!ex.getSQLState().equals("23505")) {
                        throw ex;
                    }
                    if (!item.itemID.equals("records/mccm/items/misc/token_epic.dbr") && !item.itemID.equals("records/mccm/items/misc/token_legendary.dbr")) {
                        final Object[] args = {dbTable.getTableID()};
                        final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_LOOT_ITEM_DUPLICATE", args);
                        GDMsgLogger.addWarning(msg);
                        GDMsgLogger.addWarning(ex);
                    }
                }
                ps.clearParameters();
            }
            ps.close();
            conn.commit();
        } catch (SQLException ex2) {
            throw ex2;
        }
    }

    public static List<DBLootTableItemAlloc> getByTableID(final String tableID) {
        List<DBLootTableItemAlloc> items = null;
        final String command = "SELECT * FROM GD_LOOTTABLE_ITEM WHERE TABLE_ID = ?";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, tableID);
            try (final ResultSet rs = ps.executeQuery()) {
                items = wrap(rs);
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {tableID, "GD_LOOTTABLE_ITEM"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return items;
    }

    public static List<DBLootTableItemAlloc> getByItemID(final String itemID) {
        List<DBLootTableItemAlloc> items = null;
        final String command = "SELECT * FROM GD_LOOTTABLE_ITEM WHERE ITEM_ID = ?";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, itemID);
            try (final ResultSet rs = ps.executeQuery()) {
                items = wrap(rs);
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {itemID, "GD_LOOTTABLE_ITEM"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return items;
    }

    public static boolean isCraftableItemID(final String itemID) {
        List<DBLootTableItemAlloc> items = null;
        boolean craftable = false;
        final String command = "SELECT * FROM GD_LOOTTABLE_ITEM WHERE ITEM_ID = ? AND TABLE_ID LIKE 'records/items/loottables/%/tdyn_craft%.dbr'";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, itemID);
            try (final ResultSet rs = ps.executeQuery()) {
                items = wrap(rs);
                craftable = !items.isEmpty();
                conn.commit();
            } catch (SQLException ex) {
                craftable = false;
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {itemID, "GD_LOOTTABLE_ITEM"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return craftable;
    }

    private static List<DBLootTableItemAlloc> wrap(final ResultSet rs) throws SQLException {
        final LinkedList<DBLootTableItemAlloc> list = new LinkedList<DBLootTableItemAlloc>();
        final boolean found = false;
        while (rs.next()) {
            final DBLootTableItemAlloc item = new DBLootTableItemAlloc();
            item.tableID = rs.getString(1);
            item.itemID = rs.getString(2);
            list.add(item);
        }
        return list;
    }
}
